package org.dflish.mybatis.encrypt.rewrite;

import net.sf.jsqlparser.JSQLParserException;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.dflish.mybatis.encrypt.core.CCJSQLStatementContext;
import org.dflish.mybatis.encrypt.properties.EnCryptProperties;
import org.dflish.mybatis.encrypt.rewrite.condition.EncryptCondition;
import org.dflish.mybatis.encrypt.rule.EncryptRule;

import java.util.List;

/**
 * @author liangwx
 */
public class EncryptPreParameterRewriter {

    private final EnCryptProperties properties;

    private final EncryptRule encryptRule;

    public EncryptPreParameterRewriter(EnCryptProperties properties) {
        this.properties = properties;
        encryptRule = new EncryptRule(properties);
    }

    public void rewrite(String sql, List<ParameterMapping> parameterMappings, Object parameterObject) throws JSQLParserException {

        CCJSQLStatementContext context = new CCJSQLStatementContext(sql, encryptRule);

        List<EncryptCondition> encryptConditions = context.createEncryptConditions();

        if (encryptConditions.isEmpty()) {
            return;
        }

        for (EncryptCondition each : encryptConditions) {
            encryptParameters(each, parameterMappings, parameterObject);
        }
    }

    private void encryptParameters(EncryptCondition encryptCondition, List<ParameterMapping> parameterMappings, Object parameterObject){

        int index = encryptCondition.getIndex();

        if (parameterMappings != null && parameterObject != null){
            ParameterMapping parameterMapping = parameterMappings.get(index - 1);
            String property = parameterMapping.getProperty();
            MetaObject metaObject = SystemMetaObject.forObject(parameterObject);

            String originalValues = (String) metaObject.getValue(property);

            final Object encryptedValues = encryptRule.getEncryptedValues(encryptCondition.getTableName(), encryptCondition.getColumnName(), originalValues);

            metaObject.setValue(property, encryptedValues);
        }
    }
}
